1. 正则替换 :
1
2
3
4
可替换为固定的字符串 :	
ret = pattern.sub('xxx', string)
也可以传递一个函数, 将函数的返回值替换匹配的内容
ret = pattern.sub(fn, string)
tihuan.py :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import re

string = '男生都喜欢20岁的女孩'

# ret = string.replace('18', '30')
# print(ret)

# 里面的数字无论多少都改为30,正则替换
# 将正则表达式匹配的内容替换为指定的内容
pattern = re.compile(r'\d+')
# 参数1:要替换的内容
# 参数2:在哪个字符串中查找
# ret = pattern.sub('30', string)


# 将这回调函数传递进去,该函数的要求是有一个参数,有一个返回值
# 参数就是正则匹配的对象,返回值的作用就是替换正则匹配的字符串
def fn(obj):
# print(obj)
age = int(obj.group())
age += 1
return str(age)

ret = pattern.sub(fn, string)

print(ret)
2. bs4 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
bs4是什么 ? 是一个Python的第三方模块, 用来解析html数据, 其提供的api接口非常的人性化.
安装 : pip install bs4
pip install lxml 这是一个解析器, 用来将文档生成对象
有可能出现问题 : 将pip源 切换为国内源, 国内源 : 豆瓣源, 阿里源等
如何切换国内源 :
(1) 指令切换, -i 源地址 只针对于这一次的指令
(2) 永久切换, 在指定地方写一个配置文件即可
Windows :
(1) 在文件资源管理器上面输入 %appdata%
(2) 手动创建一个pip的文件夹
(3) 新建一个文件 pip.ini
(4) 写入如下内容 :
[global]
timeout = 6000
index-url = http://pypi.douban.com/simple
trusted-host = pypi.douban.com

Linux :
(1) cd ~
(2) mkdir ~/.pip
(3) vi ~/.pip/pip.conf
(4) 编辑内容和Windows的内容一模一样
语法学习 :
from bs4 import BeautifulSoup
步骤 : 通过BeautifulSoup这个类, 可以将你的html文档生成一个对象, 然后这个对象会有一些方法供你使用, 就可以得到你想要的节点内容, 或者节点属性

可以将本地文件或者网络文件生成对象, 先从本地开始学习
(1) 根据标签名进行查找
soup.a 只能得到第一个符合要求的标签
(2) 获取属性
soup.a.attrs 返回一个字典, 里面包含所有的属性和值
soup.a.attrs['href']
soup.a['href']
(3) 获取内容
obj.string
obj.text
obj.get_text()
如果标签里只有内容, 那么三那个获取的结果都一样
如果标签里面还有标签, 那么第一个获取的是None, 后两个获取的是纯文本内容
(4)find方法
soup.find('a', title='xxx')
soup.find('a', id='xxx')
soup.find('a', class_='xxx')
返回一个对象,只能找到第一个符合要求的节点
选看: soup.find('a', class_ = re.compile(r'xxx'))
可以写正则表达式, 一般用的不多
(5) find_all方法
返回一个列表, 列表里面都是对象
用法和上面的find一样, 只不过这个是找到所有, find只是找到一个
soup.find_all('a', limit=2) 取出前两个
(6) select方法
根据选择器得到自己想要的节点
常用的选择器 :
标签选择器 a div
类选择器 .lala .dudu
id选择器 #lala #dudu
后代选择器
div .lala a : 后面的是前面的子节点就行
div > p > a : 后面的必须是前面的直接子节点才行
群组选择器 div, #lala, .dudu
属性选择器 input[name=xxx] dic[class=xxx]
返回的是一个列表, 就算选择器精确到一个, 也是一个列表, 列表中只有一个对象
也可以通过子对象来查找内容, 得到当前子对象里面符合要求的标签内容

soup是整个文档对象
soup_test.py :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试bs4</title>
</head>
<body>
<div>
阿珂
<p>李白</p>
兰陵王
<p>韩信</p>
孙悟空
</div>
<div class="tang">
<ul>
<li><a href="www.libai.com" class="bai lala" title="李白">李白乘舟将欲行,忽闻岸上踏歌声,桃花潭水深千尺,不及汪伦送我情</a></li>
<li><a href="www.dufu.com" class="du" title="望岳">会当凌绝顶,一览众山小</a></li>
<li><a href="www.dumu.com" class="du" id="后庭花">停车坐爱枫林晚,霜叶红于二月花,商女不知亡国恨,隔江犹唱后庭花</a></li>
<li><a href="www.lishangyin.com" class="shangyin">君问归期未有期,巴山夜雨涨秋池,何当共剪西窗烛,却话巴山夜雨时</a></li>
</ul>
</div>
<div class="song">
<li><a href="www.qing.com" class="suqing">寻寻觅觅,冷冷清清,凄凄惨惨戚戚</a></li>
<li><a href="www.luyou.com" class="luyou">王师北定中原日,家祭无忘告乃翁</a></li>
<li><a href="www.su.com" class="su">但愿人长久千里共婵娟</a></li>
<a href="www.xiang.com" title="xiang">人生自古谁无死,留取丹心照汗青</a>
</div>
</body>
</html>
suop.py :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from bs4 import BeautifulSoup

# 将文档生成对象
# lxml是一个解析器,官方也自带了一个解析器 html.parser, 但是一般都使用lxml,效率更高
soup = BeautifulSoup(open('soup_test.html', encoding='utf8'), 'lxml')

# 打印对象可以打印为字符串,重写一个方法叫做 __str__
# print(type(soup))


# 根据标签名进行查找
# ret = soup.a
# print(ret)
# 获取属性
# print(ret.attrs['href'])
# print(ret['href'])

# 获取内容
# print(ret.string)
# print(ret.text)
# print(ret.get_text())

# ret = soup.div

# print(ret.string)
# print(ret.text.replace('\t', '').replace('\n', ''))
# print(ret.get_text())

# ret = soup.find('a', title='望岳')
# ret = soup.find('a', class_='du')
# ret = soup.find('a', id='后庭花')
# print(ret.string)

import re

# ret = soup.find('a', class_=re.compile(r'^su'))
# print(ret)

# ret = soup.find_all('a')
# print(ret[3].string)

# ret = soup.find_all('a', class_='du')
# print(ret)

# ret = soup.find_all('a', class_=re.compile(r'^su'))
# print(ret)

# ret = soup.find_all('a', limit=2)
# print(ret)

# ret = soup.select('.song > li > a')
# ret = soup.select('.song a')

# ret = soup.select('a[title=xiang]')
# print(ret)

# ret = soup.select('a')
# print(ret)

odiv = soup.find('div', class_='song')
# print(odiv)
ret = odiv.select('a')

print(ret)
3. bs4实例 :
1
2
3
4
滚滚长江东逝水,浪花淘尽英雄,是非成败转头空,青山依旧在,几度夕阳红
白发渔樵江渚上,惯看秋月春风,一壶浊酒喜相逢,古今多少事,都付笑谈中
三国演义下载
智联招聘
sanguo.py :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import urllib.request
import time
from bs4 import BeautifulSoup

def handle_request(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
}
request = urllib.request.Request(url=url, headers=headers)
return request

def parse_first():
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
request = handle_request(url)
# 发送请求,得到响应
content = urllib.request.urlopen(request).read().decode('utf8')
# 解析内容
soup = BeautifulSoup(content, 'lxml')
# 得到所有的章节链接
oa_list = soup.select('.book-mulu > ul > li > a')
fp = open('三国演义.txt', 'w', encoding='utf8')
# print(oa_list)
# print(len(oa_list))
# 遍历列表,通过对象依次获取内容和链接
for oa in oa_list:
# 得到链接
href = 'http://www.shicimingju.com' + oa['href']
# 得到章节标题
title = oa.text
print('正在下载%s......' % title)
# 向href发送请求,通过bs得到该章节的内容
text = get_text(href)
string = title + '\n' + text + '\n'
fp.write(string)
print('结束下载%s' % title)
time.sleep(2)
fp.close()

def get_text(href):
request = handle_request(href)
content = urllib.request.urlopen(request).read().decode('utf8')
soup = BeautifulSoup(content, 'lxml')
odiv = soup.find('div', class_='chapter_content')
return odiv.text

def main():
parse_first()

if __name__ == '__main__':
main()
zhilian.py :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
import time

class ZhiLianSpider(object):
def __init__(self, jl, kw, start_page, end_page):
# 将这些都保存到成员属性中
self.jl = jl
self.kw = kw
self.start_page = start_page
self.end_page = end_page
self.url = 'https://sou.zhaopin.com/jobs/searchresult.ashx?'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
}

def run(self):
# 打开文件
self.fp = open('work.txt', 'w', encoding='utf8')
# 要爬取多页,所以需要循环爬取
for page in range(self.start_page, self.end_page + 1):
print('正在爬取第%s页......' % page)
request = self.handle_request(page)
# 发送请求,获取响应
content = urllib.request.urlopen(request).read().decode('utf8')
# 解析内容
self.parse_content(content)
print('结束爬取第%s页' % page)
time.sleep(2)
self.fp.close()

def parse_content(self, content):
# 生成soup对象
soup = BeautifulSoup(content, 'lxml')
# 提取内容
# 首先提取所有的table
otable_list = soup.find_all('table', class_='newlist')
# print(len(otable_list))
# 过滤掉表头
otable_list = otable_list[1:]
# 遍历这个列表,依次提取每一个工作的详细信息
for otable in otable_list:
# 职位名称
zwmc = otable.select('.zwmc > div > a')[0].text.rstrip('\xa0')
# 公司名称
gsmc = otable.select('.gsmc > a')[0].string
# 职位月薪
zwyx = otable.select('.zwyx')[0].string
# 工作地点
gzdd = otable.select('.gzdd')[0].string
# print(zwmc)
# exit()
# 保存到字典中
item = {
'职位名称': zwmc,
'公司名称': gsmc,
'职位月薪': zwyx,
'工作地点': gzdd,
}
self.fp.write(str(item) + '\n')

def handle_request(self, page):
# 拼接url
# 将get参数写成一个字典
data = {
'jl': self.jl,
'kw': self.kw,
'p': page
}
# 处理data
data = urllib.parse.urlencode(data)
url = self.url + data
# print(url)
request = urllib.request.Request(url=url, headers=self.headers)
return request

def main():
# 工作地点
jl = input('请输入工作地点:')
# 工作关键字
kw = input('请输入工作关键字:')
# 起始页码和结束页码
start_page = int(input('请输入起始页码:'))
end_page = int(input('请输入结束页码:'))

# 面向对象封装
zhilian = ZhiLianSpider(jl, kw, start_page, end_page)
zhilian.run()

if __name__ == '__main__':
main()
4. xpath简介 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
xml是什么? 被设计用来传输和存储数据, 和json同处一个位置, 但是目前以json居多 
xml和html的不同点 :
(1) xml用来传输数据, html用来显示数据
(2) xml的标签没有被定义, html的标签是预定义好的
(3) xml具有自我描述性
常用的路径表达式 :
/ : 从根节点开始查找
// : 从任意位置开始查找
. : 从当前节点开始查找
.. : 从父节点开始查找
@ : 选取属性
路径表达式举例 :
bookstore/book : 从bookstore下面找book节点, book必须是bookstore的直接子节点
bookstore//book : 从bookstore下面找book节点, book可以是直接子节点也可以是孙子节点
//book : 从文档中任意位置找book节点
//@lang : 查找所有拥有lang属性节点
bookstore/book[1] : 直接子节点第一个book, 下标从1开始
bookstore/book[last()] : 直接字节点最后一个book
bookstore//book[last()] : 所有book里面的最后一个
bookstore/book[last() - 1] : 倒数第二个book
bookstore/book[position() < 3] : 取出前两个
//title[@lang] : 所有拥有lang属性的title节点
//title[@lang=eng] : 所有的lang属性值为eng的title节点
bookstore/* : bookstore下面所有的直接子节点
bookstore//* : bookstore下面所有的子节点
//title[@*] : 有属性的title节点
//book/title | //book/price : 找到所有book节点下面的直接子节点title
xpath函数 :
contains : 包含
starts-with : 以某某开头
ends-with : 以某某结尾(貌似不能用)

我们学的xpath是用在了html中, 由于html和xml很像, 所以有一个第三方库就封装了使用xpath来解析html数据的接口, pip install lxml

使用的时候, 首先需要使用插件进行测试xpath, 然后再来到代码中进行编写
xpath插件使用:
(1) 属性筛选
//input[@id="kw"] 找到属性id值为kw的input节点
(2) 层级筛选
通过属性和层级筛选
//div[@id="head"]/div/div[@id="u1"]/a[2]
× 请我吃糖~
打赏二维码